// api/log_api/enter.go
// =============================================================================
// | 包: log_api                                                              |
// | 模块: 日志API                                                            |
// | 功能: 提供日志相关的API接口                                              |
// =============================================================================
package log_api

import (
	"blog_server/common"
	"blog_server/common/res" // 响应处理包 - 提供统一的HTTP响应格式
	"blog_server/global"
	"blog_server/service/log_service"
	"fmt"

	// 全局变量包 - 提供全局配置和数据库连接
	"blog_server/models"      // 数据模型包 - 提供数据模型定义
	"blog_server/models/enum" // 枚举模型包 - 提供系统中使用的枚举类型

	"github.com/gin-gonic/gin" // Web框架 - 提供HTTP路由和处理功能
)

// =============================================================================
// | 结构体: LogApi                                                           |
// | 功能: 封装日志相关的API方法，便于统一管理和调用                          |
// =============================================================================
type LogApi struct {
}

// =============================================================================
// | 结构体: LogListRequest                                                   |
// | 功能: 定义日志列表查询请求的数据结构                                     |
// | 说明: 用于绑定和验证客户端发送的查询参数                                 |
// =============================================================================
type LogListRequest struct {
	// Limit int `form:"limit"` // 每页显示的日志数量
	// Page int `form:"page"` // 当前页码
	// Key string `form:"key"` // 搜索关键字
	common.PageInfo

	// -------------------------------------------------------------------------
	// | 字段: LogType - enum.LogType                                           |
	// | 功能: 日志类型，用于筛选特定类型的日志                                 |
	// | 映射: URL查询参数中的logType字段                                       |
	// -------------------------------------------------------------------------
	LogType enum.LogType `form:"logType"` // 日志类型

	// -------------------------------------------------------------------------
	// | 字段: Level - enum.LogLevelType                                        |
	// | 功能: 日志级别，用于筛选特定级别的日志                                 |
	// | 映射: URL查询参数中的level字段                                         |
	// -------------------------------------------------------------------------
	Level enum.LogLevelType `form:"level"` // 日志级别

	// -------------------------------------------------------------------------
	// | 字段: UserID - uint                                                    |
	// | 功能: 用户ID，用于筛选特定用户的日志                                   |
	// | 映射: URL查询参数中的userID字段                                        |
	// -------------------------------------------------------------------------
	UserID uint `form:"userID"` // 用户ID

	// -------------------------------------------------------------------------
	// | 字段: IP - string                                                      |
	// | 功能: IP地址，用于筛选特定IP的访问日志                                 |
	// | 映射: URL查询参数中的ip字段                                            |
	// -------------------------------------------------------------------------
	IP string `form:"ip"` // IP地址

	// -------------------------------------------------------------------------
	// | 字段: LoginStatus - bool                                               |
	// | 功能: 登录状态，用于筛选登录成功或失败的日志                           |
	// | 映射: URL查询参数中的loginStatus字段                                   |
	// -------------------------------------------------------------------------
	LoginStatus bool `form:"loginStatus"` // 登录状态

	// -------------------------------------------------------------------------
	// | 字段: ServiceName - string                                             |
	// | 功能: 服务名称，用于筛选特定服务的日志                                 |
	// | 映射: URL查询参数中的serviceName字段                                   |
	// -------------------------------------------------------------------------
	ServiceName string `form:"serviceName"` // 服务名称
}

// =============================================================================
// | 结构体: LogListResponse                                                  |
// | 功能: 定义日志列表响应的数据结构                                         |
// | 说明: 扩展LogModel，添加用户昵称和头像信息                               |
// =============================================================================
type LogListResponse struct {
	// -------------------------------------------------------------------------
	// | 嵌入: models.LogModel                                                  |
	// | 功能: 嵌入日志模型，包含日志的基本信息                                 |
	// -------------------------------------------------------------------------
	models.LogModel

	// -------------------------------------------------------------------------
	// | 字段: UserNickname - string                                            |
	// | 功能: 用户昵称，用于在响应中显示                                       |
	// | 映射: JSON响应中的userNickname字段                                     |
	// -------------------------------------------------------------------------
	UserNickname string `json:"userNickname"` // 用户昵称

	// -------------------------------------------------------------------------
	// | 字段: UserAvatar - string                                              |
	// | 功能: 用户头像URL，用于在响应中显示                                    |
	// | 映射: JSON响应中的userAvatar字段                                       |
	// -------------------------------------------------------------------------
	UserAvatar string `json:"userAvatar"` // 用户头像
}

// =============================================================================
// | 函数: LogListView                                                        |
// | 接收者: LogApi (日志API结构体)                                           |
// | 参数: @c - *gin.Context (Gin框架的上下文对象)                            |
// | 功能: 处理GET /log/list请求，返回日志列表                                |
// | 说明: 支持分页查询和多种筛选条件                                         |
// |----------------------------------------------------------------------------|
// | 处理流程:                                                               |
// | 1. 绑定查询参数到LogListRequest结构体                                   |
// | 2. 验证和修正分页参数                                                   |
// | 3. 构造查询条件                                                         |
// | 4. 执行数据库查询                                                       |
// | 5. 构造响应数据                                                         |
// | 6. 返回JSON格式的响应                                                   |
// =============================================================================
func (LogApi) LogListView(c *gin.Context) {
	// -------------------------------------------------------------------------
	// | 步骤1: 绑定查询参数                                                    |
	// -------------------------------------------------------------------------
	// 声明LogListRequest结构体实例，用于接收和验证查询参数
	var cr LogListRequest
	// 使用ShouldBindQuery方法将URL查询参数绑定到cr结构体
	// 该方法会自动进行数据类型转换和验证(基于结构体标签)
	// 如果绑定或验证失败，err将不为nil
	err := c.ShouldBindQuery(&cr)
	// 检查绑定和验证过程中是否出现错误
	if err != nil {
		// 调用统一错误处理函数，将验证错误转换为标准格式的JSON响应
		// 参数: err(验证错误信息), c(Gin上下文)
		res.FailWithError(err, c)
		// 出现错误时直接返回，不执行后续逻辑
		return
	}

	list, count, err := common.ListQuery(models.LogModel{
		LogType:     cr.LogType,     // 日志类型筛选条件
		Level:       cr.Level,       // 日志级别筛选条件
		UserID:      cr.UserID,      // 用户ID筛选条件
		IP:          cr.IP,          // IP地址筛选条件
		LoginStatus: cr.LoginStatus, // 登录状态筛选条件
		ServiceName: cr.ServiceName, // 服务名称筛选条件
	}, common.Options{
		PageInfo:     cr.PageInfo,
		Likes:        []string{"title"},     // 模糊查询字段
		Preloads:     []string{"UserModel"}, // 预加载关联
		Debug:        true,
		DefaultOrder: "created_at desc",
	})

	// -------------------------------------------------------------------------
	// | 步骤5: 构造响应数据                                                    |
	// -------------------------------------------------------------------------
	// 声明日志列表响应切片
	var _list = make([]LogListResponse, 0)

	// 遍历查询结果，构造响应数据
	for _, logModel := range list {
		// 将日志模型转换为日志列表响应
		_list = append(_list, LogListResponse{
			LogModel:     logModel,                    // 日志基本信息
			UserNickname: logModel.UserModel.Nickname, // 用户昵称
			UserAvatar:   logModel.UserModel.Avatar,   // 用户头像
		})
	}

	// -------------------------------------------------------------------------
	// | 步骤6: 返回JSON格式的响应                                              |
	// -------------------------------------------------------------------------
	// 调用统一成功响应函数，返回日志列表和总记录数
	res.OkWithList(_list, int(count), c)

	// 显式返回，结束函数执行
	return
}

// =============================================================================
// | 函数: LogReadView                                                        |
// | 接收者: LogApi (日志API结构体)                                           |
// | 参数: @c - *gin.Context (Gin框架的上下文对象)                            |
// | 功能: 处理GET /logs/:id请求，将指定日志标记为已读                        |
// | 说明: 通过URI参数获取日志ID，更新日志的阅读状态                          |
// |----------------------------------------------------------------------------|
// | 处理流程:                                                               |
// | 1. 绑定URI参数到IDRequest结构体                                          |
// | 2. 根据ID查询日志记录                                                    |
// | 3. 检查日志是否存在                                                      |
// | 4. 如果日志未读，则更新为已读状态                                        |
// | 5. 返回操作结果                                                          |
// =============================================================================
func (LogApi) LogReadView(c *gin.Context) {
	// 绑定URI参数到IDRequest结构体
	var cr models.IDRequest
	err := c.ShouldBindUri(&cr) // 从URI中绑定ID参数
	if err != nil {
		// 参数绑定失败时返回错误响应
		res.FailWithError(err, c)
		return
	}

	// 根据ID查询日志记录
	var log models.LogModel
	err = global.DB.Take(&log, cr.ID).Error // 使用Take查询单条记录
	if err != nil {
		// 日志不存在时返回错误信息
		res.FailWithMsg("不存在的日志", c)
		return
	}

	// 如果日志未读，则更新为已读状态
	if !log.IsRead {
		global.DB.Model(&log).Update("is_read", true) // 更新阅读状态
	}
	// 返回操作成功信息
	res.OkWithMsg("日志读取成功", c)
}

// =============================================================================
// | 函数: LogRemoveView                                                      |
// | 接收者: LogApi (日志API结构体)                                           |
// | 参数: @c - *gin.Context (Gin框架的上下文对象)                            |
// | 功能: 处理DELETE /logs请求，批量删除指定的日志记录                        |
// | 说明: 通过JSON请求体获取要删除的日志ID列表，并执行删除操作                |
// |----------------------------------------------------------------------------|
// | 处理流程:                                                               |
// | 1. 绑定JSON请求体到RemoveRequest结构体                                   |
// | 2. 记录操作日志（请求和响应信息）                                        |
// | 3. 查询待删除的日志记录集合                                              |
// | 4. 执行删除操作                                                          |
// | 5. 返回删除结果和删除数量                                                |
// =============================================================================
func (LogApi) LogRemoveView(c *gin.Context) {
	// 绑定JSON请求体到RemoveRequest结构体
	var cr models.RemoveRequest
	err := c.ShouldBindJSON(&cr) // 从JSON请求体绑定ID列表
	if err != nil {
		// 参数绑定失败时返回错误响应
		res.FailWithError(err, c)
		return
	}

	// --------------------------------------------------------------------------
	// | 步骤2: 记录操作日志                                                     |
	// --------------------------------------------------------------------------
	// 获取日志服务实例，记录请求和响应信息
	log := log_service.GetLog(c)     // 获取日志服务实例
	log.ShowRequest()                // 记录请求信息
	log.ShowResponse()               // 记录响应信息

	// --------------------------------------------------------------------------
	// | 步骤3: 查询待删除的日志记录集合                                         |
	// --------------------------------------------------------------------------
	var logList []models.LogModel
	global.DB.Find(&logList, "id in ?", cr.IDList) // 查询符合ID列表的日志

	// --------------------------------------------------------------------------
	// | 步骤4: 执行删除操作                                                     |
	// --------------------------------------------------------------------------
	if len(logList) > 0 {
		global.DB.Delete(&logList) // 批量删除日志记录
	}

	// --------------------------------------------------------------------------
	// | 步骤5: 返回删除结果                                                     |
	// --------------------------------------------------------------------------
	msg := fmt.Sprintf("日志删除成功，共删除%d条", len(logList)) // 格式化结果消息
	res.OkWithMsg(msg, c) // 返回成功响应和删除数量
}
